import 'dart:io';
import 'package:dio/dio.dart';
import 'package:freedom/entity/abstract_result.dart';
import 'package:freedom/entity/restful.dart';
import 'package:freedom/entity/user_entity_info.dart';
import 'package:freedom/page/user_login_widget.dart';
import 'package:freedom/util/api_router.dart';
import 'package:freedom/util/customer_dialog.dart';
import 'package:freedom/const/business_enum.dart';
import 'package:freedom/util/navigator_provider.dart';
import 'package:freedom/util/user_util.dart';
import 'package:freedom/widget/update_dialog.dart';

typedef CallBack<T> = void Function(T data);

void defaultError(data) {}

class Http {
  static Http? _instance;
  static String? token;
  static Duration receiveTimeout = const Duration(seconds: 60);
  static Dio? _dio;
  BaseOptions? _options;

  static Http getInstance() {
    _instance ??= Http._();
    return _instance!;
  }

  Http._() {
    // 初始化 Options
    _options = BaseOptions(
        baseUrl: ApiRouter.getHttpServer(),
        sendTimeout: receiveTimeout,
        receiveTimeout: receiveTimeout,
        contentType: "application/json",
        headers: {});

    _dio = Dio(_options);

    _dio!.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
      options.headers["client-version"] = ApiRouter.clientVersion;
      UserEntityInfo? userEntityInfo = UserUtil.getUserInfo();
      if (userEntityInfo != null) {
        options.headers["Authory"] = userEntityInfo.tokenAuthority;
      }
      return handler.next(options);
    }, onResponse: (response, handler) {
      return handler.next(response);
    }, onError: (DioException e, handler) {
      return handler.next(e);
    }));
  }

  request<T>(url,
      {
      // 返回内容格式
      ResponseType? responseType,
      data,
      RequestEnum type = RequestEnum.GET,
      // 请求内容格式
      ContentType? contentType,
      cancelToken,
      // 成功回调
      CallBack<T>? success,
      // 失败回调
      Function error = defaultError,
      bool showLoading = false,
      bool showErrorMsg = false,
      String loadingMsg = "加载中..."}) async {
    contentType ??=
        ContentType("application", "x-www-form-urlencoded", charset: "utf-8");
    if (showLoading) {
      CustomerDialog.loading(loadingMsg);
    }
    Response response;
    Options options = Options(
        sendTimeout: receiveTimeout,
        receiveTimeout: receiveTimeout,
        responseType: responseType ?? ResponseType.json,
        contentType: contentType.toString());
    try {
      if (type == RequestEnum.GET) {
        response = await _dio!.get(url,
            queryParameters: data, options: options, cancelToken: cancelToken);
      } else {
        response = await _dio!.post(url, data: data, options: options);
      }
      if (showLoading) {
        CustomerDialog.closeAllLoading(groupKey: CustomerDialog.systemLoading);
      }
      var result = response.data;
      var checkType = AbstractResult.checkType(result, T) as T;
      if (null != checkType &&
          checkType is Restful &&
          checkType.code != BusinessEnum.success) {
        doErrorCode(checkType.code, showErrorMsg, checkType.msg);
        error(checkType);
      } else if (null != checkType) {
        success!(checkType);
      } else {
        success!(result);
      }
    } on DioException catch (e) {
      CustomerDialog.closeAllLoading(groupKey: CustomerDialog.systemLoading);
      if (e.type.index == 5 || e.response == null) {
        CustomerDialog.showText("网络异常");
        error(null);
        return;
      }
      String message = "";

      if (e.response?.data is String) {
        message = e.response?.data ?? "";
      } else if (e.response?.data is Map &&
          (e.response?.data as Map).containsKey("msg")) {
        message = (e.response?.data as Map)["msg"] ?? "";
      }

      if (e.response!.statusCode == HttpStatus.unauthorized) {
        message = '认证失败,请重新登录';
        NavigatorProvider.pushReplacement(UserLoginWidget());
      } else if (e.response!.statusCode != HttpStatus.ok) {
        message = message == "" ? "网络异常" : message;
      }

      if (showErrorMsg) {
        CustomerDialog.showText(message);
      }
      error(e.response?.data);
    }
  }

  void doErrorCode(String? code, bool showDialog, String? message) async {
    switch (code) {
      case BusinessEnum.updateVersion:
        CustomerDialog.showGamingDialog(
            (cancelFunc) => UpdateDialog(cancelFunc, message),
            groupKey: "updateDialog");
      default:
        if (showDialog) {
          CustomerDialog.showText(message);
        }
        break;
    }
  }
}

enum RequestEnum { POST, GET }
